﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FitnessMVC.Data;
using Moq;
using System.Web;
using System.Web.Mvc;
using FitnessMVC.Test.Fakes;
using FitnessMVCWeb.Controllers;
using System.Web.Routing;

namespace FitnessMVC.Test
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class UserProfileControllerTest
    {
        public UserProfileControllerTest()
        {
            
        }

        // Helper pattern from NerdDinner
        private UserProfileController CreateUserProfileControllerAs(string userName, IFitnessRepository repo)
        {
            var mock = new Mock<ControllerContext>();
            mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
            mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);

            var controller = new UserProfileController(repo);
            controller.ControllerContext = mock.Object;

            return controller;
        }

        [TestMethod]
        public void GetProfileDetailsByUsername_With_SameUsername_ShouldBe_Allowed()
        {
            // Arrange
            var formData = GetUserProfileFormData();

            FakeFitnessData fake = FakeFitnessData.GetFakeData();
            var data = fake.GetMockFitnessRepository();

            // Act
            UserProfileController upc = CreateUserProfileControllerAs("test1", data);
            ViewResult result = upc.Details("test1", false) as ViewResult;


            // Assert
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(UserProfile));
            Assert.AreEqual("Test1", ((UserProfile)result.ViewData.Model).FirstName);
        }

        [TestMethod]
        public void GetProfileDetailsByUserName_With_Public_Profile_By_DifferentUser_ShouldBe_Allowed()
        {
            // Arrange
            var formData = GetUserProfileFormData();

            FakeFitnessData fake = FakeFitnessData.GetFakeData();
            var data = fake.GetMockFitnessRepository();

            // Act
            UserProfileController upc = CreateUserProfileControllerAs("test1", data);
            ViewResult result = upc.Details("test2", false) as ViewResult;


            // Assert
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(UserProfile));
            Assert.AreEqual("Test2", ((UserProfile)result.ViewData.Model).FirstName);
            Assert.AreEqual("Boston, MA", ((UserProfile)result.ViewData.Model).Hometown);
        }

        [TestMethod]
        public void GetProfileDetailsByUserName_With_Private_Profile_Should_Return_Only_PictureAndName_If_RequestingUser_IsNotBuddy()
        {
            // Arrange
            FakeFitnessData fake = FakeFitnessData.GetFakeData();
            var data = fake.GetMockFitnessRepository();
            var upc = CreateUserProfileControllerAs("test1", data);

            // Act
            var result = upc.Details("test3", null) as ViewResult;

            // Assert
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(LimitedProfileInfo));
            Assert.AreEqual("test3", ((LimitedProfileInfo)result.ViewData.Model).UserName);
            Assert.AreEqual("Test3", ((LimitedProfileInfo)result.ViewData.Model).FirstName);
        }

        [TestMethod]
        public void GetProfileDetailsByUserName_With_Private_Profile_Should_Return_FullProfile_If_RequestingUser_IsBuddy()
        {
            // Arrange
            FakeFitnessData fake = FakeFitnessData.GetFakeData();
            var data = fake.GetMockFitnessRepository();
            var upc = CreateUserProfileControllerAs("test2", data);
            
            // Act
            var result = upc.Details("test3", null) as ViewResult;
 
            // Assert
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(UserProfile));
            Assert.AreEqual(false, ((UserProfile)result.ViewData.Model).IsPublic);
            Assert.AreEqual("Test3", ((UserProfile)result.ViewData.Model).FirstName);
            Assert.IsTrue(data.GetUserBuddies("test3").Any(x => x.UserName == "test2"), "Users are not buddies and a full profile was returned.");
        }

        [TestMethod]
        public void GetUserBuddies_Should_Only_Return_LoggedInUsers_Buddies_With_NoParameters()
        {
            // Arrange
            FakeFitnessData fake = FakeFitnessData.GetFakeData();
            var data = fake.GetMockFitnessRepository();
            var upc = CreateUserProfileControllerAs("test1", data);

            // Act
            var result = upc.Buddies(null, null) as ViewResult;

            // Assert
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(List<LimitedProfileInfo>));
            Assert.IsTrue(((List<LimitedProfileInfo>)result.ViewData.Model).Count > 0);
            Assert.IsTrue(((List<LimitedProfileInfo>)result.ViewData.Model)[0].FirstName == "Test2");
            Assert.IsFalse(((List<LimitedProfileInfo>)result.ViewData.Model).Any(x => x.FirstName == "Test3"));
        }

        [TestMethod]
        public void LoggedInUsers_Should_See_Their_Profile_When_NavigatingTo_ProfilePage()
        {
            // Arrange
            FakeFitnessData data = FakeFitnessData.GetFakeData();
            var repo = data.GetMockFitnessRepository();

            UserProfileController upc = CreateUserProfileControllerAs("test1", repo);

            // Act
            var result = upc.Index() as ViewResult;

            // Assert
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(UserProfile));
            Assert.AreEqual("Test1", ((UserProfile)result.ViewData.Model).FirstName);            
        }

        [TestMethod]
        public void UnauthenticatedUsers_Should_Be_RedirectedToLoginPage_When_NavigatingTo_ProfilePage()
        {
            FakeFitnessData data = FakeFitnessData.GetFakeData();
            var repo = data.GetMockFitnessRepository();

            UserProfileController upc = new UserProfileController(repo);

            // Act
            var result = upc.Index() as ViewResult;

            // Assert
            Assert.AreEqual("LogOn", result.ViewName);
        }

        [TestMethod]
        public void NewlyRegisteredUsers_Should_Redirect_To_Their_ProfilePage()
        {
            // Arrange
            FakeFitnessData data = FakeFitnessData.GetFakeData();
            var repo = data.GetMockFitnessRepository();
            
            User newUser = data.GetFakeUser();
            UserProfile newProfile = data.GetFakeUserProfile(newUser.UserId);
            newProfile.User = newUser;

            UserProfileController upc = CreateUserProfileControllerAs(newUser.UserName, repo);

            // Act
            var result = upc.Create(newProfile) as ViewResult;            

            // Assert
            Assert.IsInstanceOfType(result.ViewData.Model, typeof(UserProfile));
            Assert.AreEqual(newProfile.AboutMe, ((UserProfile)result.ViewData.Model).AboutMe);
            Assert.AreEqual(newProfile.FirstName, ((UserProfile)result.ViewData.Model).FirstName);
            Assert.AreEqual(newProfile.LastName, ((UserProfile)result.ViewData.Model).LastName);
        }

        //TODO: Test Bad UserProfile Registration.

        private FormCollection GetUserProfileFormData()
        {
            FormCollection fc = new FormCollection();            
            fc.Add("FirstName", "Form Test");
            fc.Add("LastName", "User");
            fc.Add("Birthdate", "1/1/1985");
            fc.Add("Sex", "m");
            fc.Add("Hometown", "Boston, MA");
            fc.Add("AboutMe", "I'm a test user that is used to test profiles.");
            fc.Add("MemberSince", "3/1/2009");
            fc.Add("ProfilePicID", "1");            

            return fc;
        }

        
    }
}
